Skip to content

sdk: raise NovemException on API errors instead of a print placeholder#236

Merged
bjornars merged 2 commits into
novem-code:mainfrom
bjornars:bsn/sdk-raise-on-api-error
Jun 18, 2026
Merged

sdk: raise NovemException on API errors instead of a print placeholder#236
bjornars merged 2 commits into
novem-code:mainfrom
bjornars:bsn/sdk-raise-on-api-error

Conversation

@bjornars

@bjornars bjornars commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Draft — implements the fail-hard option from #235 for discussion.

What

Adds raise_on_response(r) (api_ref) — parses the server message and any rejected lines and raises the matching NovemException subclass (401/403/404, generic NovemException otherwise) — and replaces the print("should raise a general error") placeholder in all eight write sites (vis/group/job/repo, the create_* PUT + api_write POST).

409 is treated as a platform-wide no-op (idempotency): raise_on_response returns early on 409, so the existing per-call carve-outs in api_create are now redundant but kept for clarity. Novem409 remains available for callers that want to raise it explicitly.

403s from api_write previously raised Novem403 with no message; they now flow through raise_on_response and surface the server message.

Why draft

This is the fail-hard direction from #235 — a behavioral change: writes that previously silently no-op'd on a non-2xx now raise. The open questions there should be settled before this goes ready:

  • raise on any non-ok vs 4xx-only (keep 5xx softer/retryable)
  • opt-in raise_on_error/strict flag vs hard default (existing users)
  • does it warrant a major version bump

Verified

Against a live dev API, mail.bcc = [30 addrs over the 25 cap] now raises instead of silently storing nothing:

NovemException: No recipients were changed, the request contained entries that
could not be applied [user26@example.com: …maximum of 25 external address
recipients … exceeds it.; …]

The server-side 400 that makes this observable is novem-code/gaia#2810.

Before ready

Refs #235 · SDK half of novem-code/gaia#2656

@bjornars

Copy link
Copy Markdown
Contributor Author

@sondove I know there are concerns here. Maybe find a way to opt in to hard-failures, vs the default way of just on error goto next.

@sondove

sondove commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

I mean, we should definitely not raise any exceptions on 409, that is an idiomatic response in how the novem API works.

The library will ALWAYS generate a PUT to create a novem object whenever you instantiate one (e.g. plt = Plot("novem_id"). The reason for this is that the API is idempotent, so creating an object that already exist is a NOOP. We return 409 in these cases as the item already exists, but this is a success case as far as the API is concerned.

@sondove

sondove commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Looking at this PR, i believe it's OK to go, replacing the current incomplete error handling with an exception should be fine. Those error cases have historically been deviant behavior, and an exception is a better response than a print.

Every resource write path (vis/group/job/repo `create_*` PUT and
`api_write` POST) handled 404/403/409 but, on any other non-ok response,
printed the body + headers + the literal "should raise a general error"
and returned — so the caller got no exception and silently no-op'd.

Terje hit exactly this (novem-code/gaia#2656): `mail.bcc = [over-cap list]`
returned without error while nothing was stored. The server now rejects
over-cap / unresolvable writes with a 400 + `{message, rejected:[…]}`, but
the SDK swallowed it.

Add `raise_on_response(r)` (api_ref) — parses the server `message` and any
`rejected` lines and raises the matching NovemException subclass (401/403/
404/409 → generic NovemException otherwise) — and call it from all eight
write sites. `mail.bcc = …` over the cap now raises NovemException with the
cap reason and the rejected addresses.
@bjornars bjornars force-pushed the bsn/sdk-raise-on-api-error branch from 8da8a15 to ec0f5c9 Compare June 17, 2026 09:43
@bjornars bjornars marked this pull request as ready for review June 17, 2026 10:45
@bjornars

Copy link
Copy Markdown
Contributor Author

Looking at this PR, i believe it's OK to go, replacing the current incomplete error handling with an exception should be fine. Those error cases have historically been deviant behavior, and an exception is a better response than a print.

I've fixed up the 409s, and I've got some integration tests loaded up in gaia for after merge.

@bjornars bjornars requested review from myme and sondove June 17, 2026 11:42
@bjornars bjornars merged commit 2093e2b into novem-code:main Jun 18, 2026
5 checks passed
bjornars added a commit that referenced this pull request Jun 18, 2026
Add a README "Error handling" section covering the two newest changes:

- PR #236: writes now raise NovemException (or a subclass) carrying the
  server message instead of silently printing a placeholder. Documents the
  exception hierarchy (all importable from novem.exceptions) and the create
  PUT 409 no-op for objects that already exist.
- PR #240: requests now time out instead of hanging, with the default
  (10s, 2min) and job.run() (30s, 30min) values and the resulting
  requests.exceptions.Timeout.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants